﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace lyAdmin.Entity.Bean
{
    public class BuilderFun<T>
    {
        /// <summary>
        /// 生成查询条件表达式
        /// </summary>
        /// <param name="queryBean">参数</param>
        /// <returns>表达式</returns>
        public Expression<Func<T, bool>> ParserConditions(QueryBean queryBean)
        {
            //将条件转化成表达是的Body
            var query = ParseExpressionBody(queryBean.Fields);
            var parameter = Expression.Parameter(typeof(T));
            return Expression.Lambda<Func<T, bool>>(query, parameter);
        }
        /// <summary>
        /// 生成排序表达式
        /// </summary>
        /// <param name="queryBean">参数</param>
        /// <returns>表达式</returns>
        public Expression<Func<T, int>> ParserSore(QueryBean queryBean)
        {  
            var parameter = Expression.Parameter(typeof(T));
            var propertyInfo = typeof(T).GetProperty(queryBean.Sort.Field);
            Expression propertySelector = Expression.Property(parameter, propertyInfo);

            var orderby = Expression.Lambda<Func<T, int>>(propertySelector, parameter);

            return orderby; 
        }
        private Expression ParseExpressionBody(IEnumerable<FieldsBean> fields)
        {
            if (fields == null || fields.Count() == 0)
            {
                return Expression.Constant(true, typeof(bool));
            }
            else if (fields.Count() == 1)
            {
                return ParseCondition(fields.First());
            }
            else
            {
                Expression left = ParseCondition(fields.First());
                Expression right = ParseExpressionBody(fields.Skip(1));
                return Expression.AndAlso(left, right);
            }
        }
        private Expression ParseCondition(FieldsBean field)
        {
            var parameter = Expression.Parameter(typeof(T));
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, field.Field);
            Expression value = Expression.Constant(field.Value);
            switch (field.Type)
            {
                case "like":
                    return Expression.Call(key, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), value);
                case "eq":
                    return Expression.Equal(key, Expression.Convert(value, key.Type));
                case "gt":
                    return Expression.GreaterThan(key, Expression.Convert(value, key.Type));
                case "egt":
                    return Expression.GreaterThanOrEqual(key, Expression.Convert(value, key.Type));
                case "lt":
                    return Expression.LessThan(key, Expression.Convert(value, key.Type));
                case "elt":
                    return Expression.LessThanOrEqual(key, Expression.Convert(value, key.Type));
                case "neq":
                    return Expression.NotEqual(key, Expression.Convert(value, key.Type));
                case "in":
                    return ParaseIn(p, field);
                case "between":
                    return ParaseBetween(p, field);
                default:
                    throw new NotImplementedException("不支持此操作");
            }
        }

        private Expression ParaseIn(ParameterExpression parameter, FieldsBean field)
        {
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, field.Field);
            var valueArr = field.Value.ToString().Split(',');
            Expression expression = Expression.Constant(true, typeof(bool));
            foreach (var itemVal in valueArr)
            {
                Expression value = Expression.Constant(itemVal);
                Expression right = Expression.Equal(key, Expression.Convert(value, key.Type));

                expression = Expression.Or(expression, right);
            }
            return expression;
        }

        private Expression ParaseBetween(ParameterExpression parameter, FieldsBean field)
        {
            ParameterExpression p = parameter;
            Expression key = Expression.Property(p, field.Field);
            var valueArr = field.Value.ToString().Split(',');
            if (valueArr.Length != 2)
            {
                throw new NotImplementedException("ParaseBetween参数错误");
            }
            try
            {
                DateTime.Parse(valueArr[0]);
                DateTime.Parse(valueArr[1]);
            }
            catch
            {
                throw new NotImplementedException("ParaseBetween参数只能为日期");
            }
            Expression expression = Expression.Constant(true, typeof(bool));
            //开始位置
            Expression startvalue = Expression.Constant(DateTime.Parse(valueArr[0]));
            Expression start = Expression.GreaterThanOrEqual(key, Expression.Convert(startvalue, key.Type));

            Expression endvalue = Expression.Constant(DateTime.Parse(valueArr[1]));
            Expression end = Expression.GreaterThanOrEqual(key, Expression.Convert(endvalue, key.Type));
            return Expression.AndAlso(start, end);
        }
    }
}
